#ifndef _IO_TCPACCEPT_H_
#define _IO_TCPACCEPT_H_

#include <ioeventdef.h>
#include <iotcp.hpp>

#define TCP_ACCEPT_CONNECTED		0
#define TCP_ACCEPT_FAILD			1

class IoTcpAccpet
{
public:
	IoTcpAccpet() {

		this->acceptptr = NULL;
		this->safe = NULL;
	}
	virtual ~IoTcpAccpet() {

		accpet_destory();
	}

public:
	int accpet_create(io_service* pService) {

		this->acceptptr = ALLOC_NEW io_acceptor(*pService);
		rc_assert(this->acceptptr, S_ERROR)

		this->safe = ALLOC_NEW io_strand(*pService);
		rc_assert(this->safe, S_ERROR)

		_sem_init(&this->post_sem, 0);

		post_ref.value = 0;

		return S_SUCCESS;
	}
	int accpet_destory() {

		_sem_destroy(&this->post_sem);

		rc_assert(this->acceptptr, S_ERROR)
		delete this->acceptptr;
		this->acceptptr = NULL;

		rc_assert(this->safe, S_ERROR)
		delete this->safe;
		this->safe = NULL;

		return S_SUCCESS;
	}
	int accpet_assign(_sock_t* s) {

		rc_assert(this->acceptptr, S_ERROR)
		int rc = S_SUCCESS;

		try {
			io_error_code ec;
			this->acceptptr->assign(boost::asio::ip::tcp::v4(), *s, ec);
			rc_assert_log(!ec, S_ERROR, ec.message().c_str());
			rc_assert(this->acceptptr->is_open(), S_ERROR)
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_ERROR;
		}
		return rc;
	}
	int accpet_close() {

		rc_assert(this->acceptptr, S_ERROR)
		rc_assert(this->acceptptr->is_open(), S_ERROR)
		int rc = S_SUCCESS;

		try {
			this->acceptptr->close();
			this->accept_wait_sem();
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_ERROR;
		}
		return rc;
	}
	int	accpet_listen() {

		rc_assert(this->acceptptr, S_ERROR)
		int rc = S_SUCCESS;

		try {
			io_error_code ec;
			this->acceptptr->listen(boost::asio::socket_base::max_connections, ec);
			rc_assert(!ec, S_ERROR)
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_ERROR;
		}
		return rc;
	}
	int	accpet_bind(const char* addr, unsigned short port) {

		rc_assert(this->acceptptr, S_ERROR)
		int rc = S_SUCCESS;

		try {
			io_error_code ec;
			this->acceptptr->bind(tcp::endpoint(boost::asio::ip::address::from_string(addr), port), ec);
			rc_assert(!ec, S_ERROR)
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_ERROR;
		}
		return rc;
	}
	int	accpet_wait(const IoTcpBase* tcp, void* data) {

		rc_assert(this->acceptptr, S_ERROR)

		this->accept_add_ref();

		this->acceptptr->async_accept(*tcp->ptr,
			safe->wrap(boost::bind(&IoTcpAccpet::accept_handle,
				this,
				boost::asio::placeholders::error,
				data,
				tcp)));


		return S_SUCCESS;
	}
	int accept_is_open() {

		rc_assert(this->acceptptr->is_open(), S_ERROR)
		return S_SUCCESS;
	}
	int accept_handle(io_c_error_code ec, void* data, const IoTcpBase* tcp) {

		this->accept_del_ref();
		int rc = S_SUCCESS;

		try {
			if (ec) {
				loge("accept error %ld", this->post_ref);
				this->AcceptCB(data, TCP_ACCEPT_FAILD, 0);
			} else {
				this->AcceptCB(data, TCP_ACCEPT_CONNECTED, tcp->ptr->native_handle());
			}
		} catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_ERROR;
		}

		if (post_ref.value == 0)
		{
			accept_post_sem();
		}

		return rc;
	}
	long accept_add_ref() {

		return _atomic_add(&this->post_ref);
	}
	long accept_del_ref() {

		return _atomic_del(&this->post_ref);
	}
	void accept_wait_sem() {

		_sem_wait(&this->post_sem);
	}
	void accept_post_sem() {

		_sem_post(&this->post_sem);
	}

	io_acceptor_ptr		acceptptr;
	io_strand_ptr		safe;

	_atomic_t			post_ref;
	_sem_t				post_sem;

public: 
	virtual void AcceptCB(void *data, event_id error_code, _sock_t s) = 0;
};

#endif 
